﻿using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MugenInjection;
using MugenInjection.Interface;
using Should;

namespace MugenInjectionTest.Core
{
    public partial class InjectorBinderTest
    {
        [TestMethod]
        public void NonGenericRebindWithParametersTest()
        {
            var bindType = typeof(string);
            var parameters = new IInjectionParameter[1];
            const string value = "value";

            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty).When(context => context.Parameters == parameters);
                injector.Get<string>(parameters).ShouldEqual(string.Empty);
                injector.Rebind(bindType, parameters).ToConstant(value);
                injector.Get<string>().ShouldEqual(value);
            }
        }

        [TestMethod]
        public void TestNonGenericRebind()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            var bindType = typeof(string);


            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty).When(context => context.SpecialParameters == dict);
                Assert.AreEqual(injector.Get<string>(dict), string.Empty);
                injector.Rebind(bindType, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters);
                Assert.AreEqual(injector.Get<string>(dict, parameters), string.Empty);
                injector.Rebind(bindType, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name), string.Empty);
                injector.Rebind(bindType, name).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name, dict), string.Empty);
                injector.Rebind(bindType, name, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name, dict, parameters), string.Empty);
                injector.Rebind(bindType, name, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Unbind all
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty).When(
                    context => context.SpecialParameters == dict && context.Parameters == parameters).NamedBinding(name);
                injector.Bind<string>().ToConstant(string.Empty).When(
                    context => context.SpecialParameters == dict && context.Parameters == parameters);
                injector.Bind<string>().ToConstant(string.Empty);
                Assert.AreEqual(injector.GetAll<string>().Count(), 3);
                injector.Rebind(bindType).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
        }

        [TestMethod]
        public void TestNonGenericRebindInto()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";
            var bindType = typeof(string);

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.Parameters == parameters && context.TypeInto == TypeInto.AsType() &&
                        context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, null, parameters), string.Empty);
                injector.RebindInto(bindType, TypeInto, ParameterInfo, null, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() &&
                        context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, dict), string.Empty);
                injector.RebindInto(bindType, TypeInto, ParameterInfo, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.Parameters == parameters &&
                        context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, dict, parameters), string.Empty);
                injector.RebindInto(bindType, TypeInto, ParameterInfo, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo), string.Empty);
                injector.RebindInto(bindType, name, TypeInto, ParameterInfo).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() &&
                        context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo, dict), string.Empty);
                injector.RebindInto(bindType, name, TypeInto, ParameterInfo, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.Parameters == parameters &&
                        context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo, dict, parameters), string.Empty);
                injector.RebindInto(bindType, name, TypeInto, ParameterInfo, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
        }

        [TestMethod]
        public void TestGenericRebind()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty).When(context => context.Parameters == parameters);
                Assert.AreEqual(injector.Get<string>(parameters), string.Empty);
                injector.Rebind<string>(parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty).When(context => context.SpecialParameters == dict);
                Assert.AreEqual(injector.Get<string>(dict), string.Empty);
                injector.Rebind<string>(dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters);
                Assert.AreEqual(injector.Get<string>(dict, parameters), string.Empty);
                injector.Rebind<string>(dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name), string.Empty);
                injector.Rebind<string>(name).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.SpecialParameters == dict)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name, dict), string.Empty);
                injector.Rebind<string>(name, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.SpecialParameters == dict && context.Parameters == parameters)
                    .NamedBinding(name);
                Assert.AreEqual(injector.Get<string>(name, dict, parameters), string.Empty);
                injector.Rebind<string>(name, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Unbind all
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>().ToConstant(string.Empty).When(
                    context => context.SpecialParameters == dict && context.Parameters == parameters).NamedBinding(name);
                injector.Bind<string>().ToConstant(string.Empty).When(
                    context => context.SpecialParameters == dict && context.Parameters == parameters);
                injector.Bind<string>().ToConstant(string.Empty);
                Assert.AreEqual(injector.GetAll<string>().Count(), 3);
                injector.Rebind<string>().ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
        }

        [TestMethod]
        public void TestGenericRebindInto()
        {
            var parameters = new IInjectionParameter[1];
            var dict = new Dictionary<string, object>();
            const string name = "test";
            const string value = "value";

            //Only parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.Parameters == parameters && context.TypeInto == TypeInto.AsType() &&
                        context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, null, parameters), string.Empty);
                injector.RebindInto<string>(TypeInto, ParameterInfo, null, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() &&
                        context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, dict), string.Empty);
                injector.RebindInto<string>(TypeInto, ParameterInfo, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.Parameters == parameters &&
                        context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo);
                Assert.AreEqual(injector.GetInto<string>(TypeInto, ParameterInfo, dict, parameters), string.Empty);
                injector.RebindInto<string>(TypeInto, ParameterInfo, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(context => context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo), string.Empty);
                injector.RebindInto<string>(name, TypeInto, ParameterInfo).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters.
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.TypeInto == TypeInto.AsType() &&
                        context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo, dict), string.Empty);
                injector.RebindInto<string>(name, TypeInto, ParameterInfo, dict).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
            //Only named binding and special parameters and parameters
            using (MugenInjector injector = GetInjector())
            {
                injector.Bind<string>()
                    .ToConstant(string.Empty)
                    .When(
                        context =>
                        context.SpecialParameters == dict && context.Parameters == parameters &&
                        context.TypeInto == TypeInto.AsType() && context.ParameterInfo == ParameterInfo)
                    .NamedBinding(name);
                Assert.AreEqual(injector.GetInto<string>(name, TypeInto, ParameterInfo, dict, parameters), string.Empty);
                injector.RebindInto<string>(name, TypeInto, ParameterInfo, dict, parameters).ToConstant(value);
                Assert.AreEqual(injector.Get<string>(), value);
            }
        }
    }
}